﻿using LuaFramework;
using LuaInterface;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum EntityType
{
	Lord = 1,
	Hero = 2,
}
public class CEntity : MonoBehaviour
{
	[NoToLua]
	public int entityId;
	[NoToLua]
	public EntityType entityType;
	public float moveSpeed = 2;
	public float rotateSpeed = 360;
	public MoveSystem moveSystem;
	private EntityAreaComponent areaComp;
	public bool isDie;
	private Material hideMat;
	private Dictionary<Renderer, Material[]> normalMats = new Dictionary<Renderer, Material[]>();
	private Material outLineMat;
	//
	private bool isUpdateRotate;
	private Quaternion endRot;

	public float attackRadius = 1;
	public float searchRadius = 2;

	public float bodyRadius = 1;
	public float collisionRadius
	{
		get { return bodyRadius + 0.1f; }
	}
	private LuaTable luaTable;

	private static int areaUnique;
	private static int MIN_AREA = 3;
	private static int MAX_AREA = 31;
	private static int GetArea()
	{
		for(int i = MIN_AREA; i <= MAX_AREA; i++)
		{
			if((areaUnique & (1<<i)) == 0)
			{
				areaUnique |= 1 << i;
				return i;
			}
		}
		return 0;

	}
	private void Awake()
	{
		var collider = gameObject.AddComponent<CharacterController>();
		collider.radius = bodyRadius;
		collider.height = 3;
		collider.center = new Vector3(0, 1.5f, 0);

		moveSystem = gameObject.AddComponent<MoveSystem>();
		entityId = gameObject.GetInstanceID();
	}
	private void Start()
	{
		//StartCoroutine(SetAreaComp());
		//int area = GetArea();
		//moveSystem.bottomArea = area;
		//areaComp = EntityAreaComponent.Create(transform.parent);
		//areaComp.Bind(this, moveSystem.bottomArea);
		//areaComp.gameObject.name = "area" + entityId;
	}
	private IEnumerator SetAreaComp()
	{
		yield return new WaitForSeconds(1);
		if (isDie) yield break;
		int area = GetArea();
		moveSystem.bottomArea = area;
		areaComp = EntityAreaComponent.Create(transform.parent);
		areaComp.Bind(this, moveSystem.bottomArea);
		areaComp.gameObject.name = "area" + entityId;
	}
	public void SetEntityId(int id)
	{
		entityId = id;
		CEntityMgr.Ins.Add(this);
	}
	public void SetEntityType(int type)
	{
		entityType = (EntityType)type;
	}
	
	public void SetDie()
	{
		if (isDie) return;
		isDie = true;
		if (areaComp != null)
			Destroy(areaComp.gameObject);
		areaUnique &= ~(1<<moveSystem.bottomArea);
		if(CEntityMgr.Ins!= null)
			CEntityMgr.Ins.Remove(this);
		SetOutLine(false);
	}
	private Material[] GetMat(Material[] normalMat)
	{
		if(hideMat != null)
		{
			if (outLineMat != null)
				return new Material[] { hideMat, outLineMat };
			else
				return new Material[] { hideMat };
		}
		else
		{
			if(outLineMat != null)
			{
				var ms = new Material[normalMat.Length + 1];
				System.Array.Copy(normalMat, ms, normalMat.Length);
				ms[ms.Length - 1] = outLineMat;
				return ms;
			}
		}
		return normalMat;
	}
	public void SetOutLine(bool isOutLine) 
	{
		InitNormalMat();
		if (isOutLine) {
			if (outLineMat != null) return;
			outLineMat = ResourceManager.Ins.GetMaterialPool("Material/outline.mat");
		} else
		{
			if (outLineMat == null) return;
			ResourceManager.Ins.ReturnPool("Material/outline.mat", outLineMat);
			outLineMat = null;
		}
		foreach (var v in normalMats)
		{
			v.Key.materials = GetMat(v.Value);
		}
	}
	
	public void SetHide(bool isHide)
	{
		InitNormalMat();
		if (isHide)
		{
			if (hideMat != null) return;
			hideMat = ResourceManager.Ins.GetMaterialPool("Material/Hide.mat");
		}
		else
		{
			if (hideMat == null) return;
			ResourceManager.Ins.ReturnPool("Material/Hide.mat", hideMat);
			hideMat = null;
		}
		bool isFirst = true;
		foreach (var v in normalMats)
		{
			if (isHide && isFirst)
			{
				hideMat.SetTexture("_MainTex", v.Value[0].GetTexture("_MainTex"));
				hideMat.SetTexture("_BumpMap", v.Value[0].GetTexture("_BumpMap"));
				isFirst = false;
			}
			v.Key.materials = GetMat(v.Value);
		}
	}
	private void InitNormalMat()
	{
		if (normalMats.Count != 0) return;
		var mesh = GetComponentsInChildren<Renderer>();
		if (mesh == null || mesh.Length == 0) return;
		for (int i = 0; i < mesh.Length; i++)
		{
			normalMats[mesh[i]] = mesh[i].sharedMaterials;
		}
	}
	public void AddForce(Vector3 force)
	{
		moveSystem.AddForce(force);
	}
	public void SetLuaTable(LuaTable tb)
	{
		luaTable = tb;
	}
	public void SetRotateSpeed(float speed)
	{
		rotateSpeed = speed;
	}
	public void SetMoveSpeed(float speed)
	{
		moveSpeed = speed;
	}
	public void StartRotate(float forwardX,float forwardY,float forwardZ)
	{
		StartRotate(new Vector3(forwardX, forwardY,forwardZ));
	}
	public void StartRotate(Vector3 forward)
	{
		isUpdateRotate = true;
		endRot = Quaternion.LookRotation(forward);
	}
	public void StopRotate()
	{
		isUpdateRotate = false; 
	}
	public void PosChanged()
	{
		if (luaTable == null) return;
		var f = luaTable.GetLuaFunction("ctol_PosChanged");
		if (f == null) return;
		Vector3 pos = transform.position;
		f.Call(luaTable, pos.x, pos.y,pos.z); 
		f.Dispose();
	}
	public void MovingChaned(bool isMove)
	{
		if (luaTable == null) return;
		var f = luaTable.GetLuaFunction("ctol_SetMoving");
		if (f == null) return;
		Vector3 pos = transform.position;
		f.Call(luaTable,isMove);
		f.Dispose();
	}
	public void ForwardChanged()
	{
		if (luaTable == null) return;
		var f = luaTable.GetLuaFunction("ctol_ForwardChanged");
		if (f == null) return;
		Vector3 forward = transform.forward;
		f.Call(luaTable, forward.x, forward.y, forward.z);
		f.Dispose();
	}
	[NoToLua]
	public void SkillAnimationEvent( string eventId,string eventValue)
	{
		if (luaTable == null) return;
		var f = luaTable.GetLuaFunction("ctol_SkillAnimationEvent");
		if (f == null) return;
		f.Call(luaTable, eventId,eventValue);
		f.Dispose();
	}
	[NoToLua]
	public void SetGrass(int id,bool isIn)
	{
		if (luaTable == null) return;
		var f = luaTable.GetLuaFunction("SetGrass");
		if (f == null) return;
		f.Call(luaTable,id, isIn);
		f.Dispose();
	}
	[NoToLua]
	public void Tick()
    {
		moveSystem.Tick();
		if (!isUpdateRotate) return;
		if (transform.rotation != endRot)
		{
			transform.rotation = Quaternion.RotateTowards(transform.rotation, endRot, rotateSpeed * Time.deltaTime);
			ForwardChanged();
		}
		else
		{
			isUpdateRotate = false;
		}
	}
	
	private void OnDestroy()
	{
		if (luaTable != null)
			luaTable.Dispose();
		luaTable = null;
		SetDie();
	}
#if UNITY_EDITOR
	private void OnDrawGizmos()
	{
		if (!CEntityMgr.Ins || !CEntityMgr.Ins.debug) return;
		UnityEditor.Handles.color = new Color(0.464f, 0.438f, 1, 0.1f);
		UnityEditor.Handles.DrawSolidDisc(transform.position, Vector3.up, searchRadius);
		UnityEditor.Handles.color = new Color(0.36f, 1, 0.4f, 0.1f);
		UnityEditor.Handles.DrawSolidDisc(transform.position + new Vector3(0, 0.01f, 0), Vector3.up, attackRadius);
	}
#endif 
}

